
//Copyright 1997-2009 Syrinx Development, Inc.
//This file is part of the Syrinx Web Application Framework (SWAF).
// == BEGIN LICENSE ==
//
// Licensed under the terms of any of the following licenses at your
// choice:
//
//  - GNU General Public License Version 3 or later (the "GPL")
//    http://www.gnu.org/licenses/gpl.html
//
//  - GNU Lesser General Public License Version 3 or later (the "LGPL")
//    http://www.gnu.org/licenses/lgpl.html
//
//  - Mozilla Public License Version 1.1 or later (the "MPL")
//    http://www.mozilla.org/MPL/MPL-1.1.html
//
// == END LICENSE ==
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;


using Swaf;
using Swaf.BizObj;
using Swaf.BizRule;
using Swaf.Config;
using Swaf.Container;

namespace Approval.Decorators
{
	
	public class ApprovalBaseRuleDecorator : IApprovalDecorator
	{
		protected IBizObj m_approvalInfo;
		protected IBizObj m_company;


		public IApplication App { get { return Application.currentApp; } }

		public ApprovalBaseRuleDecorator(IBizObj ruleInfo, IBizObj approvalInfo)
		{
			if (approvalInfo != null)
				m_approvalInfo = approvalInfo;
			IRuleManagerEx mngr = Application.globalApp.ruleMgr as IRuleManagerEx;
			mngr.getRuleInfo(ruleInfo.get("ruleName").ToString()).Decorators.Add(GetType().Name, this);
		}
				
		protected virtual void executePostRuleExecution(IRunningRule info, ref object ruleReturn, ref Exception ruleException)
		{
			//intentionally left blank for the derive class to implement
		}

		protected virtual bool executePreRuleExecution(IRunningRule info)
		{
			return true;
		}

		protected virtual string RuleName
		{
			get { return ""; }
		}

		protected bool EditMode
		{
			get 
			{
				if (Swaf.Application.currentApp.sessionData["ApprovalEditMode"] != null)
					return ((bool)Swaf.Application.currentApp.sessionData["ApprovalEditMode"]);
				else
					return false;
			}
		}
		#region IRuleDecorator Members

		public void postRuleExecution(Swaf.BizRule.IRunningRule info, ref object ruleReturn, ref Exception ruleException)
		{
			executePostRuleExecution(info, ref ruleReturn, ref ruleException);
		}

		public bool preRuleExecution(Swaf.BizRule.IRunningRule info)
		{
			return executePreRuleExecution(info);
		}

		#endregion

		#region IDecorator Members

		public bool IsStandin
		{
			get { return true; }
		}

		public string Name
		{
			get { return RuleName; }
		}

		public string Value
		{
			get {return "";}
		}

		public object decorateInstance(object theInst)
		{
			return theInst;
		}

		#endregion
	}
	
	public class GetListActionRuleManager : ApprovalBaseRuleDecorator
	{
		public GetListActionRuleManager(IBizObj ruleInfo, IBizObj approvalInfo) : base(ruleInfo, approvalInfo) { }

		protected override void executePostRuleExecution(IRunningRule info, ref object ruleReturn, ref Exception ruleException)
		{
			try
			{
				if (ruleReturn != null && ruleException == null)
				{
					IApplication app = null;
					Swaf.BGuid.Guid parentId = null;
					object[] inputParams = info.inputParams as object[];
					if (inputParams != null && inputParams.Length > 2 && inputParams[2] is Swaf.BGuid.Guid)
					{
						app = inputParams[0] as IApplication;
						parentId = inputParams[2] as Swaf.BGuid.Guid;
					}
					IBizObjList returnList = ruleReturn as IBizObjList;
					IResults rc = Application.currentApp.ruleMgr.execute("checkForCompanyApproval");
					if (rc.ExceptionInfo == null && rc.CallResults is IBizObj)
					{
						IBizObj company = rc.CallResults as IBizObj;
						if (company != null && parentId != null)
						{
							if (returnList != null)
							{
								string typeName = returnList.objectType.Name;
								rc = app.ruleMgr.execute("getApprovalData", typeName, parentId);
								if (rc.ExceptionInfo == null && rc.CallResults is IBizObjList)
								{
									IBizObjList list = rc.CallResults as IBizObjList;
									if (list.numElements > 0)
									{
										for (int i = 0; i < returnList.numElements; i++)
										{
											IBizObj ad = list.search("id", returnList[i].get("id"));
											if (ad != null)
											{
												if ("true".Equals(ad.get("override").ToString().ToLower()))
													returnList[i] = ad;
												list.Remove(ad);
											}
										}
										for (int j = 0; j < list.numElements; j++)
										   returnList.Add(list[j]);
									}
								}
							}
						}
					}
				}
			}
			catch (Exception e)
			{
				throw new ApprovalException("error executing GetListActionRuleManager for Approval.Decorator", e);
			}
		}
		
		protected override bool executePreRuleExecution(IRunningRule info)
		{
			return base.executePreRuleExecution(info);
		}
		protected override string RuleName
		{
			get
			{
				string ruleName = "";
				if (m_approvalInfo != null && m_approvalInfo.containsField("getListRuleName"))
					ruleName = m_approvalInfo.get("getListRuleName") as string;
				return ruleName;
			}
		}
		
	}

	public class GetDetailsActionRuleManager : ApprovalBaseRuleDecorator
	{
		protected IBizObj m_ruleInfo;
		protected IBizObj m_approvalInfo;
		public GetDetailsActionRuleManager(IBizObj ruleInfo, IBizObj approvalInfo)
			: base(ruleInfo, approvalInfo)
		{
			m_ruleInfo = ruleInfo;
			m_approvalInfo = approvalInfo;
		}

		protected override void executePostRuleExecution(IRunningRule info, ref object ruleReturn, ref Exception ruleException)
		{
			try
			{
				if (ruleReturn != null && ruleException == null)
				{
					IApplication app = null;
					Swaf.BGuid.Guid parentId = null;
					object[] inputParams = info.inputParams as object[];
					if (inputParams != null && inputParams.Length > 2 && inputParams[2] is Swaf.BGuid.Guid)
					{
						app = inputParams[0] as IApplication;
						parentId = inputParams[2] as Swaf.BGuid.Guid;

					}
				}
			}
			catch (Exception e) { }
			

			//base.executePostRuleExecution(info, ref ruleReturn, ref ruleException);
		}
	}
	public class AddActionRuleManager : ApprovalBaseRuleDecorator
	{
		protected string m_parentFieldName;
		public AddActionRuleManager(IBizObj ruleInfo, IBizObj approvalInfo) : base(ruleInfo, approvalInfo)
		{
			if (approvalInfo != null && approvalInfo.containsField("parentFieldId"))
				m_parentFieldName = approvalInfo.get("parentFieldId").ToString();
			
		}
		protected override void executePostRuleExecution(IRunningRule info, ref object ruleReturn, ref Exception ruleException)
		{
			//todo: check for errors that might occur in the rule call and  rollback 
		}
		protected override bool executePreRuleExecution(IRunningRule info)
		{
			ApprovalDecoratorActionHelper adah = new ApprovalDecoratorActionHelper(info);
			return adah.executeOriginalRule("Add",m_parentFieldName);
		}
	}

	public class UpdateActionRuleManager : ApprovalBaseRuleDecorator
	{
		protected string m_parentFieldName;
		public UpdateActionRuleManager(IBizObj ruleInfo, IBizObj approvalInfo) : base(ruleInfo, approvalInfo) 
		{
			if (approvalInfo != null)
				m_parentFieldName = approvalInfo.get("parentFieldId").ToString();
		}

		protected override bool executePreRuleExecution(IRunningRule info)
		{
			ApprovalDecoratorActionHelper adah = new ApprovalDecoratorActionHelper(info);
			return adah.executeOriginalRule("Update",m_parentFieldName);
		}
		protected override void executePostRuleExecution(IRunningRule info, ref object ruleReturn, ref Exception ruleException)
		{
			if (ruleException != null)
			{
				object[] inputParams = (object[])info.inputParams;
				if (inputParams != null && inputParams.Length > 2)
				{
					IApplication app = inputParams[0] as IApplication;
					IRuleContext context = inputParams[1] as IRuleContext;
					IBizObj theBizObj = inputParams[2] as IBizObj;
					context.put("PostRuleExecutionRollBackCall", 1);
					IResults rc = app.ruleMgr.execute(context,"executeApprovalAction", theBizObj, ApprovalActionState.Rollback);
				}
			}
		}
	}

	public class DeleteActionRuleManager : ApprovalBaseRuleDecorator
	{
		protected string m_parentFieldName = "";
		public DeleteActionRuleManager(IBizObj ruleInfo, IBizObj approvalInfo) : base(ruleInfo, approvalInfo) 
		{
			if (approvalInfo != null && approvalInfo.containsField("parentFieldId"))
				m_parentFieldName = approvalInfo.get("parentFieldId").ToString();
		}
		protected override bool executePreRuleExecution(IRunningRule info)
		{
			ApprovalDecoratorActionHelper adah = new ApprovalDecoratorActionHelper(info);
			return adah.executeOriginalRule("Delete", m_parentFieldName);
		}
	}

	public class ApprovalDecoratorActionHelper
	{
		protected IRunningRule m_ruleInfo;
		public ApprovalDecoratorActionHelper(IRunningRule ruleInfo) { m_ruleInfo = ruleInfo; }
		public bool executeOriginalRule(string actionType,string parentFieldName)
		{
			try
			{
				object[] inputParams = (object[])m_ruleInfo.inputParams;
				if (inputParams != null && inputParams.Length > 2)
				{
					IApplication app = inputParams[0] as IApplication;
					IRuleContext context = inputParams[1] as IRuleContext;
					IBizObj theBizObj = inputParams[2] as IBizObj;
					if (theBizObj != null)
					{
						IBizObj company = verifyCompanyApproval();
						if (company != null)
							if ("True".Equals(company.get("hasApproval").ToString()) && getApprovalState(company) == Approval.CompanyApprovalState.Enable)
							{
								if (parentFieldName != null)
								{
									//NameAddressStack ns = new NameAddressStack(m);
									//ns.push(app.sessionData);
									//Swaf.BGuid.Guid parentId = ns.get(parentFieldName) as Swaf.BGuid.Guid;
									Swaf.BGuid.Guid parentId = null;
									IBizObj appInfo = null;
									IApprovalManager mngr = app.appData["sysObjs-Approval"] as IApprovalManager;
									if (mngr != null)
									{
										appInfo = mngr.ApprovalInfos.search("id", theBizObj.type.Name);
										if (appInfo == null)
											foreach (IBizObj info in mngr.ApprovalInfos)
												if (info != null && info.get("set").Equals(theBizObj.type.Name))
												{
													appInfo = info;
													break;
												}
									}

									if (appInfo == null)
										throw new Exception("Invalid Approval Info configuration.");
									
									Dictionary<Swaf.BGuid.Guid, IBizObj> objslistDictionary = new Dictionary<Swaf.BGuid.Guid, IBizObj>();
									List<bool> results = new List<bool>();
									string bizObjTypeName = theBizObj.type.Name;
									
									if (appInfo.get("set")!= null)
									{
										bizObjTypeName = appInfo.get("id").ToString();
										IBizObjList subs = theBizObj.get(appInfo.get("subs").ToString()) as IBizObjList;
										IBizObj master = theBizObj.get(appInfo.get("master").ToString()) as IBizObj;
										objslistDictionary.Add(master.get("id") as Swaf.BGuid.Guid, master);
										foreach (IBizObj obj in subs)
											if (!obj.get(parentFieldName).Equals(Swaf.BGuid.Guid.Empty))
												objslistDictionary.Add(obj.get("id") as Swaf.BGuid.Guid, obj);
									}
									else
									{
										if (theBizObj.containsField(parentFieldName))
											parentId = theBizObj.get(parentFieldName) as Swaf.BGuid.Guid;
										objslistDictionary.Add(parentId, theBizObj);
									}
									
									foreach (KeyValuePair<Swaf.BGuid.Guid, IBizObj> bizobj in objslistDictionary)
									{
										IResults rc = app.ruleMgr.execute("getApprovalSet",bizObjTypeName, bizobj.Value.get("id") as Swaf.BGuid.Guid);
										if (rc.ExceptionInfo == null)
										{
											if (rc.CallResults == null)
											{
												results.Add(true);
												continue;
											}
											context.put("actionType", actionType);
											rc = app.ruleMgr.execute(context, "setupApprovalData", m_ruleInfo.Info.Name, bizobj, rc.CallResults as IBizObj);
											if (rc.ExceptionInfo == null && rc.CallResults is bool)
											{
												results.Add((bool)rc.CallResults);
												continue;
											}
										}
										results.Add(false);
										continue;
									}
									if (results.Contains(false))
										return false;
									
								}
							}
					}
					return true;
				}
				throw new Exception("required param is null");
			}
			catch (Exception e)
			{
				throw new ApprovalException("error on ApprovalDecoratorActionHelper.",e);
			}
			
		}
		protected IBizObj verifyCompanyApproval()
		{
			IResults rc = Application.currentApp.ruleMgr.execute("checkForCompanyApproval");
			if (rc.ExceptionInfo == null && rc.CallResults is IBizObj)
				return rc.CallResults as IBizObj;
			return null;

		}
		protected Approval.CompanyApprovalState getApprovalState(IBizObj company)
		{
			if (company != null)
			{
				if (Convert.ToInt16(company.get("approvalState")) == 1)
					return Approval.CompanyApprovalState.Enable;
				if (Convert.ToInt16(company.get("approvalState")) == 2)
					return Approval.CompanyApprovalState.NotSet;
			}
			return Approval.CompanyApprovalState.Disable;
		}
	}
	
}
